/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-04
 * V4.0
 */
package com.jphenix.driver.log.systemouta;

import com.jphenix.driver.log.executetimevoa.ExecuteTimeVO;
import com.jphenix.driver.log.util.LogUtil;
import com.jphenix.standard.beans.IShadow;
import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.log.ILog;
import com.jphenix.standard.log.ILogShadow;

import java.io.PrintStream;
import java.lang.reflect.Constructor;

/**
 * 系统输出日志类
 * 
 * 2018-07-18 顺带修改了日志输出相关方法
 * 2018-07-30 增加了输出自定义日志内容（无用） 
 * 2019-03-06 增加了输出sql语句的方法（带是否输出日志，是否写日志参数）
 * 2019-03-15 按照接口增加了输出sql语句并写入自定义文件方法（无用）
 * 2020-08-20 按照修改后的接口，将日志编码格式拆分成输出控制台日志编码格式和写文件日志编码格式
 * 2021-09-11 增加了日志提示标题入参
 * 2022-09-07 去掉了烦人的日志
 * 
 * @author 刘虻
 * 2009-12-3 下午04:51:41
 */
@ClassInfo({"2022-09-07 15:22","系统输出日志类"})
public class SystemOutLog implements ILog,IShadow {

    protected ILogShadow ls;					//影子类
	protected Object logBoss = null;			//调用日志类
	
	/**
	 * 构造函数
	 * @author 刘虻
	 */
	public SystemOutLog() {
		super();
	}
	
	/**
	 * 设置调用日志类
	 * 刘虻
	 * 2009-12-4 上午11:16:40
	 * @param logBoss 调用日志类
	 */
	public void setLogBoss(Object logBoss) {
		this.logBoss = logBoss;
	}

	/**
	 * 设置影子类
	 * 刘虻
	 * 2009-12-4 上午11:12:53
	 * @param ls 影子类
	 */
	public void setShadow(ILogShadow ls) {
		this.ls = ls;
	}
	
	/**
	 * 获取影子类
	 * 刘虻
	 * 2009-12-4 上午11:12:43
	 * @return 影子类
	 */
	public ILogShadow getShadow() {
		if(ls==null) {
			ls = new SystemOutLogShadow();
		}
		return ls;
	}
	
	
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2009-12-3 下午04:51:41
	 */
	@Override
    public void error(Object content, Object e) {
		if(getShadow().isOutError()) {
			out(fixContent("error",null,content,null),System.err);
		}
	}
	
	
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2010-4-28 下午02:37:15
	 */
	public void error(
			Object content,Object e,Class<?> exceptionCls) throws Exception {
		//输出日志内容
		String info = fixContent("error",null,content,e);
		if(getShadow().isOutError()) {
			out(info,System.err);
		}
		try {
			//获取构造函数
			@SuppressWarnings("rawtypes")
            Constructor constructor = 
				exceptionCls.getConstructor(String.class);
			//抛出异常
			throw (Exception)constructor.newInstance(new Object[] {info});
		}catch(Exception ee) {}
	}
	

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2009-12-3 下午04:51:41
	 */
	@Override
    public String getConsoleEncoding() {
		return getShadow().getConsoleEncoding();
	}
	
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2009-12-3 下午04:51:41
	 */
	@Override
	public String getFileEncoding() {
		return getShadow().getFileEncoding();
	}
	
	/**
	 * 输出日志信息
	 * 刘虻
	 * 2009-12-4 上午11:29:12
	 * @param content 日志内容
	 * @param ps 输出流
	 */
	protected void out(Object content,PrintStream ps) {
		try {
      if(content==null) {
        ps.write("null".getBytes());
      }else {
        ps.write(content.toString().getBytes(getShadow().getConsoleEncoding()));
      }
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 处理日志内容
	 * 刘虻
	 * 2009-12-4 上午11:30:07
	 * @param head    日志头
   * @param title   日志提示标题
	 * @param content 未处理的日志内容
	 * @param e       异常，或者放入调用类用来输出堆栈信息
	 * @return 处理后的日志内容
	 */
	public String fixContent(String head,String title,Object content,Object e) {
		//构建返回值
		StringBuffer reSbf = new StringBuffer();
		reSbf
			.append("S>[")
			.append(getShadow().now())
			.append("] [")
			.append(head)
			.append("] [")
			.append(getBossName())
			.append("] [")
			.append(content)
			.append("] \n");
		if(e!=null) {
			if(e instanceof Exception) {
				reSbf.append(LogUtil.getExceptionString((Exception)e));
			}else {
				reSbf.append(LogUtil.getStackTraceString(e));
			}
		}
		return reSbf.append("\n").toString();
	}

	
	/**
	 * 获取调用类名
	 * 刘虻
	 * 2009-12-4 下午04:43:56
	 * @return 调用类名
	 */
	protected String getBossName() {
		if(logBoss==null) {
			return "";
		}
		return logBoss.getClass().getName();
	}
	
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2009-12-3 下午04:51:41
	 */
	@Override
    public void log(Object content) {
		if(getShadow().isOutLog()) {
			out(fixContent("log",null,content,null),System.out);
		}
	}

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2009-12-3 下午04:51:41
	 */
	@Override
    public void log(String title,Object content) {
		if(getShadow().isOutLog()) {
			out(fixContent("log",title,content,null),System.out);
		}
	}

  /**
   * 覆盖方法
   */
  @Override
  public void info(Object content) {
      if(getShadow().isOutInfo()) {
          out(fixContent("info",null,content,null),System.out);
      }
  }
	
/**
   * 覆盖方法
   */
  @Override
  public void info(String title,Object content) {
      if(getShadow().isOutInfo()) {
          out(fixContent("info",title,content,null),System.out);
      }
  }

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2009-12-3 下午04:51:41
	 */
	@Override
    public Object runBefore() {
		return new ExecuteTimeVO();
	}

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2009-12-3 下午04:51:41
	 */
	@Override
    public void sqlLog(Object sql) {
		if(getShadow().isOutSql()) {
			out(fixContent("sql",null,sql,null),System.out);
		}
	}

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2009-12-3 下午04:51:42
	 */
	@Override
    public void startLog(Object content) {
		if(getShadow().isOutStart() && content!=null) {
			out(fixContent("start",null,content.toString(),null),System.out);
		}
	}

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2009-12-3 下午04:51:42
	 */
	@Override
    public void warning(Object content, Object e) {
		if(getShadow().isOutWarning()) {
			out(fixContent("warning",null,content,e),System.out);
		}
	}

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2009-12-3 下午04:51:42
	 */
	@Override
    public void writeRuntime(Object executeTimeVo, String title) {
		if(getShadow().isOutSql()) {
			out(">["+getShadow().now()+"] ["
					+getBossName()+"] ["+title+"] [Used Time] ["
					+((ExecuteTimeVO)executeTimeVo).getRunTime()
					+"] [ms]\n",System.out);
		}
	}
	
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2009-12-7 上午10:34:04
	 */
	@Override
    @SuppressWarnings("unchecked")
	public <T> T shadowInstance() {
		//构建返回值
		SystemOutLog reLog = new SystemOutLog();
		reLog.setShadow(getShadow());
		return (T)reLog;
	}

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2010-9-10 下午04:53:35
	 */
	@Override
  public void destroy() {}
	
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2010-9-10 下午04:53:35
	 */
	@Override
  public void debug(Object content) {}

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2010-9-10 下午04:53:35
	 */
	@Override
  public void debug(String title,Object content) {}

	/**
	 * 覆盖方法
	 * 刘虻
	 * 2010-9-10 下午04:53:35
	 */
	public boolean debugMode() {
		return false;
	}


	/**
	 * 覆盖方法
	 * 刘虻
	 * 2010-9-10 下午04:53:35
	 */
	@Override
	public void dataLog(Object content) {
		if(getShadow().isOutData()) {
			out(fixContent("data",null,content,null),System.out);
		}
	}


	/**
	 * 输出内部调试日志
	 * @param content 日志内容
	 */
	@Override
	public void tlog(Object content) {
		if(getShadow().isOutTLog()) {
			out(fixContent("nd",null,content,null),System.out);
		}
	}

	/**
	 * 输出内部调试日志
   * @param title   日志提示标题
	 * @param content 日志内容
	 */
	@Override
	public void tlog(String title,Object content) {
		if(getShadow().isOutTLog()) {
			out(fixContent("nd",title,content,null),System.out);
		}
	}
	
	/**
	 * 设置故障码
	 */
	@Override
	public void setAlertCode(String alertCode) {}
	
	/**
	 * 输出自定义日志
	 */
	@Override
	public void olog(Object content,String fileKey) {}
	
	/**
	 * 输出自定义日志
	 */
	@Override
	public void olog(String title,Object content,String fileKey) {}

	/**
	 * 输出sql语句日志
	 * @param sql       sql语句
	 * @param outSql    是否输出日志到控制台
	 * @param writeSql  是否将日志写入到文件
	 * 2019年3月6日
	 * @author MBG
	 */
	@Override
	public void sqlLog(Object sql,boolean outSql,boolean writeSql) {
		if(outSql) {
			out(fixContent("sql",null,sql,null),System.out);
		}
	}
	
	
	/**
	 * 输出sql语句日志
	 * @param sql       sql语句
	 * @param outSql    是否输出日志到控制台
	 * @param fileKey   写入文件的文件名（不带扩展名）
	 * 2019年3月15日
	 * @author MBG
	 */
	@Override
	public void sqlLog(Object sql,boolean outSql,String fileKey) {
		if(outSql) {
			out(fixContent("sql",null,sql,null),System.out);
		}
	}
}
